/**
 ******************************************************************************
 * @file           : main.c
 * @brief          : USART Printf Example
 ******************************************************************************
 * @attention
 *
 * USART串口通信和printf重定向示例
 * 功能：
 *   - USART初始化
 *   - 串口发送接收
 *   - printf重定向到串口
 *   - 接收回调处理
 *
 ******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "stm32h7xx.h"
#include <stdio.h>
#include <string.h>

/* Private defines -----------------------------------------------------------*/
#define USART_PORT      USART1
#define USART_BAUDRATE  115200

/* Private variables ---------------------------------------------------------*/
static uint8_t rx_buffer[256];
static uint16_t rx_index = 0;

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
void usart_init(uint32_t baudrate);
void usart_send_byte(uint8_t byte);
void usart_send_string(const char *str);
uint8_t usart_receive_byte(void);
void usart_rx_callback(uint8_t data);

/* Private functions ---------------------------------------------------------*/

/**
 * @brief       USART初始化
 *
 * @param[in]   baudrate - 波特率
 *
 * @retval      无
 */
void usart_init(uint32_t baudrate)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    UART_HandleTypeDef huart1 = {0};

    /* 使能GPIO和USART时钟 */
    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_USART1_CLK_ENABLE();

    /* 配置TX引脚 (PA9) */
    GPIO_InitStruct.Pin = GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* 配置RX引脚 (PA10) */
    GPIO_InitStruct.Pin = GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* 配置USART */
    huart1.Instance = USART1;
    huart1.Init.BaudRate = baudrate;
    huart1.Init.WordLength = UART_WORDLENGTH_8B;
    huart1.Init.StopBits = UART_STOPBITS_1;
    huart1.Init.Parity = UART_PARITY_NONE;
    huart1.Init.Mode = UART_MODE_TX_RX;
    huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart1.Init.OverSampling = UART_OVERSAMPLING_16;
    huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
    huart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;
    huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;

    HAL_UART_Init(&huart1);

    /* 使能接收中断 */
    HAL_UART_Receive_IT(&huart1, rx_buffer, 1);
}

/**
 * @brief       发送单字节
 *
 * @param[in]   byte - 要发送的字节
 *
 * @retval      无
 */
void usart_send_byte(uint8_t byte)
{
    while(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TXE) == RESET);
    USART1->TDR = byte;
}

/**
 * @brief       发送字符串
 *
 * @param[in]   str - 字符串指针
 *
 * @retval      无
 */
void usart_send_string(const char *str)
{
    while(*str)
    {
        usart_send_byte(*str++);
    }
}

/**
 * @brief       接收单字节（阻塞）
 *
 * @param       无
 *
 * @retval      uint8_t - 接收到的字节
 */
uint8_t usart_receive_byte(void)
{
    while(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE) == RESET);
    return USART1->RDR;
}

/**
 * @brief       接收回调函数
 *
 * @param[in]   data - 接收到的数据
 *
 * @retval      无
 */
void usart_rx_callback(uint8_t data)
{
    /* 处理接收到的数据 */
    if(data == '\r' || data == '\n')
    {
        printf("\r\nReceived: ");
        for(int i = 0; i < rx_index; i++)
        {
            printf("%c", rx_buffer[i]);
        }
        printf("\r\n");
        rx_index = 0;
    }
    else if(rx_index < sizeof(rx_buffer) - 1)
    {
        rx_buffer[rx_index++] = data;
    }
}

/**
 * @brief       printf重定向
 *
 * @param[in]   ch - 字符
 * @param[in]   f - 文件指针
 *
 * @retval      int - 字符
 */
int fputc(int ch, FILE *f)
{
    usart_send_byte((uint8_t)ch);
    return ch;
}

/**
 * @brief       系统时钟配置
 *
 * @param       无
 *
 * @retval      无
 */
void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

    /* 配置HSE */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLM = 5;
    RCC_OscInitStruct.PLL.PLLN = 160;
    RCC_OscInitStruct.PLL.PLLP = 2;
    RCC_OscInitStruct.PLL.PLLQ = 4;
    RCC_OscInitStruct.PLL.PLLR = 2;
    RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL_RANGE_VCO_250_500M;
    RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL_VCORANGE_WIDE;
    RCC_OscInitStruct.PLL.PLLFRACN = 0;
    HAL_RCC_OscConfig(&RCC_OscInitStruct);

    /* 配置时钟分频 */
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
                                  | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
    HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4);
}

/**
 * @brief       主函数
 *
 * @param       无
 *
 * @retval      int
 */
int main(void)
{
    /* 初始化 */
    HAL_Init();
    SystemClock_Config();
    usart_init(USART_BAUDRATE);

    /* 打印欢迎信息 */
    printf("\r\n");
    printf("================================\r\n");
    printf("STM32H7xx USART Printf Example\r\n");
    printf("================================\r\n");
    printf("Baudrate: %d\r\n", USART_BAUDRATE);
    printf("System Clock: %ld Hz\r\n", SystemCoreClock);
    printf("\r\n");

    /* 主循环 */
    uint32_t counter = 0;
    while(1)
    {
        /* 每秒打印一次信息 */
        printf("Counter: %ld, Time: %ld ms\r\n", counter++, HAL_GetTick());
        HAL_Delay(1000);

        /* 打印一些示例数据 */
        if(counter % 5 == 0)
        {
            printf("Temperature: 25.5°C\r\n");
            printf("Humidity: 60.0%%\r\n");
            printf("Pressure: 1013.25 hPa\r\n");
            printf("\r\n");
        }
    }

    return 0;
}

/**
 * @brief       USART中断处理
 *
 * @param       无
 *
 * @retval      无
 */
void USART1_IRQHandler(void)
{
    if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE))
    {
        uint8_t data = USART1->RDR;
        usart_rx_callback(data);
    }
}
